#ifndef PARSERXML_H_
#define PARSERXML_H_

#include <list>
#include <stdlib.h>
#include <stdio.h>
#include <libxml/parser.h>  /*trabaja con los ficheros xml*/
#include <libxml/tree.h>    /*trabaja con el árbol generado de parsear el xml*/
#include <libxml/xinclude.h>
#include <libxml/xmlIO.h>
#include <iostream>
#include <string>

#include "../Modelo/ElementoCircuital.h"
#include "../Modelo/And.h"
#include "../Modelo/Or.h"
#include "../Modelo/Not.h"
#include "../Modelo/Xor.h"
#include "../Modelo/Entrada.h"
#include "../Modelo/Salida.h"
#include "../Modelo/Compuerta.h"
#include "../Modelo/Conexion.h"
#include "../Modelo/ElementoExterno.h"
#include "../Modelo/Cable.h"
#include "../Modelo/PuntoQuiebre.h"
#include "../Comunicaciones/Cliente.h"
#include "ConexionTemp.h"
#include "ConexionesTempExternos.h"

//----CONSTANTES-----//
#define ERROR_PARSEANDO -1
#define AND "And"
#define OR "Or"
#define XOR "Xor"
#define NOT "Not"
#define ENTR "Entrada"
#define SAL "Salida"
#define CONEX "Conexion"

#define COMP "ListaDeComponentes"
#define COMPUERTAS "ListaDeCompuertas"
#define ENTRADAS "ListaDeEntradas"
#define SALIDAS "ListaDeSalidas"
#define CONEXIONES "ListaDeConexiones"
#define CABLES "ListaDeCables"
#define ELEMENTOS_EXTERNOS "ListaDeElementosExternos"
#define CIRCUITO "Circuito"

#define ID "id"
#define NRO_ENTRADA "nro_entrada"
#define NRO_SALIDA "nro_salida"
#define EMISOR "emisor"
#define RECEPTOR "receptor"
#define TIME "tiempo"
#define ENTRADA_1 "entrada_1"
#define ENTRADA_2 "entrada_2"
#define POS_X "pos_X"
#define POS_Y "pos_Y"
#define ANGULO "angulo"
#define ENTRADA "entrada"
#define ESTADO "estado"
#define CABLE "cable"
#define QUIEBRE "quiebre"
#define PORT "port"
#define IP "ip"
#define NOMBRE "nombre"

#define CANT_ENT "cantEntradas"
#define CANT_SAL "cantSalidas"
#define EXTERNO "externo"
#define DATOS "datos"

class ParserXml
{
private:	
	std::list<ConexionTemp*> * conexionesTemp;
	std::list<ConexionesTempExternos*> * conexionesTempExternos;
	std::list<Conexion*> * conexiones;
public:
	
	ParserXml();
	virtual ~ParserXml();
		
/* Obtiene desde un ruta dada el archivo contenido en un archivo .xml y vuelca los datos que contiene
 * en las listas correspondientes 
 * Pre: Listas creadas y ruta archivo valida
 * Post: -
 */
	int obtener_Desde_Archivo(char* rutaArchivo, std::list<Compuerta*> * pListaCompuertas, std::list<Entrada*> * pListaEntradas,
						std::list<Salida*>* pListaSalidas, std::list<Cable*>* pListaCables,
						std::list<ElementoExterno*>* pListaExternos, std::string * nombre);

/* Toma los datos contenidos en las distintas listas y los vuelca en una archivo con extension
 * xml. 
 * Pre: -
 * Post: -
 */
	int persistir_En_Archivo(char * rutaArchivo, std::list<Compuerta*> * pListaCompuertas, std::list<Entrada*> * pListaEntradas,
						std::list<Salida*>* pListaSalidas, std::list<Cable*>* pListaCables
						,std::list<ElementoExterno*>* pListaExternos, std::string * nombre, int nro_id);

/* Obtiene desde un xmlDocPtr dado el archivo contenido en un archivo .xml y vuelca los datos que contiene
 * en las listas correspondientes(llama a obtener_Desde_Archivo)
 * Pre:- Listas creadas y ruta archivo valida
 * Post:-
 */
	int obtener_desde_docPtr(xmlDocPtr p_xml, std::list<Compuerta*> * pListaCompuertas, std::list<Entrada*> * pListaEntradas,
			std::list<Salida*>* pListaSalidas, std::list<Cable*>* pListaCables
			,std::list<ElementoExterno*>* pListaExternos, std::string * nombre);

/* Una vez en la lista de elementos correspondientes voy iterando en los subnodos, para llamar a setear_ y
 * una vez que el elemento esta creado lo agrego a su correspondiente lista.
 * Pre: Listas creadas y nodo valido
 * Post:-
 */
	void agregar_compuertas(xmlNodePtr node, std::list<Compuerta*> * pListaCompuertas);
	void agregar_entradas(xmlNodePtr node, std::list<Entrada*> * pListaEntradas);
	void agregar_salidas(xmlNodePtr node, std::list<Salida*> * pListaSalidas);
	void agregar_cables(xmlNodePtr node, std::list<Cable*> * pListaCables);
	void agregar_elementos_externos(xmlNodePtr node,std::list<ElementoExterno*>* pListaExternos);
	void agregar_conexiones(xmlNodePtr node, std::list<Compuerta*> * pListaCompuertas, std::list<Entrada*> * pListaEntradas
												, std::list<Salida*> * pListaSalidas, std::list<ElementoExterno*>* pListaExternos);
	int agregar_Propiedades_Circuito(xmlNodePtr node, std::string * nombre);

/* Leo el correspondiente elemento que se indica en el nombre del metodo desde el nodo del XML y luego de
 * crearlo con los valores leidos en el caso de que el elemento tenga punteros a conexiones,
 * guardo las mismas en las listas temporales para luego mapear el id con el elemento real.
 * Pre:-
 * Post:-
 */
	Compuerta * setear_compuerta(xmlNodePtr compuertaXML);
	Entrada * setear_entrada(xmlNodePtr entradaXML);
	Salida * setear_salida(xmlNodePtr salidaXML);
	Cable * setear_cable(xmlNodePtr cableXML/*, pListaCables*/);
	ElementoExterno* setear_elemento_externo(xmlNodePtr externoXML, std::list<ElementoExterno*>* pListaExternos, Cliente * cliente);
	Conexion * setear_conexion(xmlNodePtr conexionXML, std::list<Compuerta*> * pListaCompuertas, std::list<Entrada*> * pListaEntradas
											, std::list<Salida*> * pListaSalidas,std::list<ElementoExterno*>* pListaExternos);

/* Busca en las listas pasadas como parametro el id indicado, de no encontrarlo devuevle NULL
 * Pre: -
 * Post:-
 */
	ElementoCircuital * buscar_por_id(int id_a_buscar, std::list<Compuerta*> * pListaCompuertas, std::list<Entrada*> * pListaEntradas
											, std::list<Salida*> * pListaSalidas);
	Conexion * buscar_por_id_conexion(int id_conexion);
	ElementoExterno* buscar_por_id(int id_a_buscar, std::list<ElementoExterno*>* pListaExternos);

/* Estos metodos recogen los datos guardados en las listas temporales de elementos e hidratan
 * los Elementos de las listas que eran punteros a null hasta este metodo con su respectivo
 * objeto.
 * Pre: -
 * Post: -
 */
	void mapear_entradas_elementos(std::list<Compuerta*> * pListaCompuertas, std::list<Entrada*> *pListaEntradas 
											, std::list<Salida*> *pListaSalidas);
	void mapear_elementos_externos(std::list<ElementoExterno*>* pListaExternos);

/* Estos metodos toman los datos de las listas recibidas como parametros y nutren los nodos que se le indican.
 * Pre: -
 * Post:-
 */
	void guardar_compuertas(xmlNodePtr root,std::list<Compuerta*>* pListaCompuertas,
									std::list<Conexion*> * pListaConexiones);	
	void guardar_entradas(xmlNodePtr root,std::list<Entrada*>* pListaEntradas,
		std::list<Conexion*>* pListaConexiones);
	void guardar_salidas(xmlNodePtr root,std::list<Salida*>* pListaSalidas,
		std::list<Conexion*>* pListaConexiones);
	void guardar_conexiones(xmlNodePtr root,std::list<Conexion*>* pListaConexiones);
	void guardar_cables(xmlNodePtr root,std::list<Cable*>* pListaCables);
	void guardar_elementos_externos(xmlNodePtr root, std::list<ElementoExterno*>* pListaExternos,
						std::list<Conexion*> * pListaConexiones	);
	void guardar_propiedades_circuito(xmlNodePtr node, std::string * nombre,int nro_id);

/* Este metodo funcional engloba una lista de nodos comunes para todos los elementos
 * Pre: -
 * Post:-
 */
	void setearPropDeInterfaz(xmlNodePtr node,ElementoCircuital * pGenerico);
};

#endif /*PARSERXML_H_*/
